
#include "dios_impl.h"
#include "./dios_ssp_hpf/dios_ssp_hpf_api.h"
#include "./dios_ssp_aec/dios_ssp_aec_api.h"
#include "./dios_ssp_ns/dios_ssp_ns_api.h"
#include <stdlib.h>
#include <stdio.h>
#include "custom_support.h"

#define FRAMESIZE 128

typedef struct {
    /* handle of each module */
	void* ptr_aec;	
	void* ptr_hpf;
    void* ptr_ns;
	
    /* necessary buffer definition */
	float* ptr_mic_buf;
	float* ptr_ref_buf;
	float* ptr_data_buf;

    /* necessary variables */
    int cfg_frame_len;
    int cfg_mic_num;
    int cfg_ref_num;
    
    /* necessary variables */
    int dt_st;
    
} objDios_ssp;

void *dios_create()
{
    int i;
	void* ptr = NULL;
	ptr = (void*)athena_calloc(1, sizeof(objDios_ssp));
	objDios_ssp* srv = (objDios_ssp*)ptr;
    
    // params init
    srv->cfg_frame_len = FRAMESIZE;
    srv->cfg_mic_num = 1;
    srv->cfg_ref_num = 1;

    // signal process modules init    
    srv->ptr_hpf = dios_ssp_hpf_init_api();    
    srv->ptr_aec = dios_ssp_aec_init_api(srv->cfg_mic_num, srv->cfg_ref_num, srv->cfg_frame_len);
    dios_ssp_aec_config_api(srv->ptr_aec, 1);  // 0: communication mode; 1: asr mode    
    srv->ptr_ns = dios_ssp_ns_init_api(srv->cfg_frame_len);

    // allocate memory
    srv->ptr_mic_buf = (float*)athena_calloc(srv->cfg_mic_num * srv->cfg_frame_len, sizeof(float));
    srv->ptr_ref_buf = (float*)athena_calloc(srv->cfg_ref_num * srv->cfg_frame_len, sizeof(float));
    srv->ptr_data_buf = (float*)athena_calloc(srv->cfg_frame_len, sizeof(float));

    // variables init 
    srv->dt_st = 1;
    dios_ssp_hpf_reset_api(srv->ptr_hpf);
    dios_ssp_aec_reset_api(srv->ptr_aec);
    dios_ssp_ns_reset_api(srv->ptr_ns);
	return ptr;    
}


int dios_process_frame(void *obj, short *mic, short *ref, short *aec)
{
    objDios_ssp* srv = (objDios_ssp*)obj;
    int ret;
    int i, j;
   
    // get input data, single-channel or multi-channel, with or without reference

    for (i=0; i<FRAMESIZE; i++) {
        srv->ptr_mic_buf[i] = (float)mic[i];
        srv->ptr_ref_buf[i] = (float)ref[i];
    }
    ret = dios_ssp_hpf_process_api(srv->ptr_hpf, srv->ptr_mic_buf, srv->cfg_frame_len);

    ret = dios_ssp_aec_process_api(srv->ptr_aec, srv->ptr_mic_buf, srv->ptr_ref_buf, &srv->dt_st);

    ret = dios_ssp_ns_process(srv->ptr_ns, srv->ptr_mic_buf);

    // get output data for wakeup
    for(j = 0; j < srv->cfg_frame_len; j++)
    {
        aec[j] = (short)(srv->ptr_mic_buf[j]);
    }
    
    return 0;
}

void dios_destroy(void *obj)
{
    objDios_ssp* srv = (objDios_ssp*)obj;
    int ret;

    /* free memory */
    if(srv->ptr_mic_buf != NULL)
    {
        athena_free(srv->ptr_mic_buf);
        srv->ptr_mic_buf = NULL;
    }
    if(srv->ptr_ref_buf != NULL)
    {
        athena_free(srv->ptr_ref_buf);
        srv->ptr_ref_buf = NULL;
    }
    if(srv->ptr_data_buf != NULL)
    {
        athena_free(srv->ptr_data_buf);
        srv->ptr_data_buf = NULL;
    }

    ret = dios_ssp_hpf_uninit_api(srv->ptr_hpf);    
    ret = dios_ssp_aec_uninit_api(srv->ptr_aec);
    ret = dios_ssp_ns_uninit_api(srv->ptr_ns);

    athena_free(srv);	
}
